﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Kugar.Core.ExtMethod
{
    public static class RunAsyncDelegateExt
    {
        /// <summary>
        ///     在控件上异步执行一个委托
        /// </summary>
        /// <param name="ctrl">源控件</param>
        /// <param name="fAsyncDelegate">需要异步执行的委托</param>
        public static void RunAsyncDelegate(this Control ctrl, Action fAsyncDelegate)
        {
            RunAsyncDelegate(ctrl, fAsyncDelegate, null);
        }

        /// <summary>
        ///     在控件上异步执行一个委托
        /// </summary>
        /// <param name="ctrl">源控件</param>
        /// <param name="fAsyncDelegate">需要异步执行的委托</param>
        /// <param name="fCallBackDelegate">当异步调用完成之后,回调的函数</param>
        public static void RunAsyncDelegate(this Control ctrl, Action fAsyncDelegate, Action fCallBackDelegate)
        {
            using (var backgroundWorker = new BackgroundWorker())
            {
                var tempHander = new RunAsyncDelegateHandler(ctrl, fAsyncDelegate, fCallBackDelegate);

                backgroundWorker.DoWork += tempHander.OnDoWork;

                backgroundWorker.RunWorkerCompleted += tempHander.OnRunWorkerCompleted;

                backgroundWorker.RunWorkerAsync();
            }
        }

        /// <summary>
        ///     使用这个类作为处理异步的类,是为了在完成事件之后,,可以注销BackgroundWorker对象上的处理委托,防止BackgroundWorker无法回收
        /// </summary>
        private class RunAsyncDelegateHandler
        {
            public RunAsyncDelegateHandler(Control srcControl, Action onRunWorkerCompleted, Action onDoWork)
            {
                SrcControl = srcControl;
                RunWorkerCompletedCallBack = onRunWorkerCompleted;
                DoWorkCallBack = onDoWork;
            }

            public Control SrcControl { set; get; }

            public Action RunWorkerCompletedCallBack { private set; get; }

            public Action DoWorkCallBack { private set; get; }

            public void OnDoWork(object o, DoWorkEventArgs workerEventArgs)
            {
                if (DoWorkCallBack != null)
                {
                    DoWorkCallBack.Invoke();
                }

                if (o is BackgroundWorker)
                {
                    ((BackgroundWorker)o).DoWork -= this.OnDoWork;
                }
            }

            public void OnRunWorkerCompleted(object o, RunWorkerCompletedEventArgs e)
            {
                if (o is BackgroundWorker)
                {
                    ((BackgroundWorker)o).RunWorkerCompleted -= this.OnRunWorkerCompleted;
                }

                if (RunWorkerCompletedCallBack != null)
                {
                    SrcControl.BeginInvoke(RunWorkerCompletedCallBack);
                }

            }
        }
    }
}
